<?php
/**
 * 视图处理类
 *
 * @package     View
 * @author      lajox <lajox@19www.com>
 */
namespace Took;
class View
{

    public $vars = array(); //模板变量
    public $const = array(); //系统常量如__WEB__$const['WEB'];
    public $tplFile = null; //模版文件
    public $compileFile = null; //编译文件
    public $content; //模板编译内容
    public $driver = null; //驱动引擎
    public static $factory = null; //静态工厂实例

    /**
     * 构造函数
     */
    public function __construct(){}

    protected function __init(){}

    /**
     * 单例模式
     */
    public static function factory()
    {
        //只实例化一个对象
        if (is_null(self::$factory)) {
            self::$factory = new View();
            self::$factory->driver = \Took\View\ViewFactory::factory();
        }
        return self::$factory;
    }

    /**
     * 验证缓存是否过期
     *
     * @param string $cachePath 缓存目录
     * @return bool
     */
    public function isCache($cachePath = null)
    {
        $cachePath = $cachePath ? $cachePath : TEMP_CACHE_PATH;
        $cacheName = md5($_SERVER['REQUEST_URI']);
        return S(
            $cacheName, false, null,
            array("dir" => $cachePath, "driver" => "file")
        ) ? true : false;
    }

    /**
     * 获得模版文件
     *
     * @param $file 模板文件
     * @return bool|string
     */
    private function getTemplateFile($file)
    {
        $file = get_view_file($file);
        //模板文件检测
        if (is_file($file)) {
            return $file;
        } else {
            DEBUG && halt("模板不存在:$file");
            return false;
        }
    }

    /**
     * 向模板中传入变量
     *
     * @param string|array $var 变量名
     * @param mixed $value 变量值
     * @return bool
     */
    public function assign($var, $value)
    {
        if (is_array($var)) {
            foreach ($var as $k => $v) {
                if (is_string($k)) {
                    $this->vars[$k] = $v;
                }
            }
        } else {
            $this->vars[$var] = $value;
        }
    }

    /**
     * 模板显示
     *
     * @param string $tplFile 模板文件
     * @param string $cachePath 缓存目录
     * @param int $cacheTime 缓存时间
     * @param string $contentType 文件类型
     * @param bool $show 是否显示
     * @return bool|string
     */
    public function display($tplFile = null, $cacheTime = -1, $cachePath = null, $contentType = "text/html", $show = true)
    {
        //缓存文件名
        $cacheName = md5($_SERVER['REQUEST_URI']);
        //缓存时间
        $cacheTime = is_numeric($cacheTime) ? $cacheTime  : intval( C("TPL_CACHE_TIME") );
        //缓存路径
        $cachePath = $cachePath ? $cachePath : TEMP_CACHE_PATH;
        //内容
        $content = null;
        if ($cacheTime >= 0) {
            $content = S($cacheName, false, $cacheTime, array("dir" => $cachePath, 'zip' => false, "driver" => "file"));
        }
        //缓存失效
        if (!$content) {
            //全局变量定义 模板使用{$took.get.xx}方式调用
            $_g = 'took';
            $this->vars[$_g]['get'] = &$_GET;
            $this->vars[$_g]['post'] = &$_POST;
            $this->vars[$_g]['request'] = &$_REQUEST;
            $this->vars[$_g]['cookie'] = &$_COOKIE;
            $this->vars[$_g]['session'] = &$_SESSION;
            $this->vars[$_g]['server'] = &$_SERVER;
            $this->vars[$_g]['config'] = C();
            $this->vars[$_g]['language'] = L();
            $this->vars[$_g]['const'] = get_defined_constants();
            //获得模板文件
            $this->tplFile = $this->getTemplateFile($tplFile);
            if (!$this->tplFile) {
                return;
            }
            //编译文件
            $this->compileFile = TEMP_COMPILE_PATH . MODULE . '/' . CONTROLLER . '/' . ACTION . '_' . substr(md5($this->tplFile), 0, 8) . '.php';
            //记录模板编译文件
            if (DEBUG) {
                \Took\Debug::$tpl[] = array(basename($this->tplFile), $this->compileFile);
            }

            //编译模板文件内容
            $content = $this->compiler();
            //创建缓存
            if ($cacheTime >= 0) {
                //写入缓存
                S($cacheName, $content, $cacheTime, array("dir" => $cachePath, 'zip' => false, "driver" => "file"));
            }
        }
        if ($show) {
            $charset = C('TPL_CHARSET') ? C('TPL_CHARSET') : "UTF-8";
            if (!headers_sent()) {
                header("Content-type:" . $contentType . ';charset=' . $charset);
            }
            echo $content;
        } else {
            return $content;
        }
    }

    /**
     * 获得视图内容
     *
     * @param null $tplFile 模板文件
     * @param null $cacheTime 缓存时间
     * @param null $cachePath 缓存路径
     * @param string $contentType 文档类型
     * @return bool|string
     */
    public function fetch($tplFile = null, $cacheTime = null, $cachePath = null, $contentType = "text/html")
    {
        return $this->display($tplFile, $cacheTime, $cachePath, $contentType, false);
    }

    //执行编译
    public function compiler() {
        //模板内容
        $this->content = file_get_contents($this->tplFile);
        //编译文件失效（不存在或过期）
        if ($this->compileInvalid()) {
            //编译是否失效
            if ($this->compileInvalid()) {
                if(is_array($this->driver)) {
                    $i = 0;
                    foreach($this->driver as $driver) {
                        $content = $i>0 ? $this->getContent() : $this->content;
                        $driver->run($this, $content);
                        $i++;
                    }
                }
                else {
                    $this->driver->run($this, $this->content);
                }
            }
        }
        $content = $this->getContent();
        return $content;
    }

    public function getContent($loadvars = false) {
        //加载全局变量
        static $loaded = false;
        if($loadvars || !$loaded) {
            if (!empty($this->vars)) {
                extract($this->vars);
            }
            $loaded = true;
        }
        ob_start();
        include($this->compileFile);
        $content = ob_get_clean();
        return $content;
    }

    /**
     * 编译是否失效
     *
     * @return bool true 失效
     */
    private function compileInvalid()
    {
        $tplFile = $this->tplFile;
        $compileFile = $this->compileFile;
        return DEBUG || !file_exists($compileFile) || (filemtime($tplFile) > filemtime($compileFile));
    }

    public function savefile($content = null, $file = null) {
        $content = is_null($content) ? $this->content : $content;
        $file = is_null($file) ? $this->compileFile : $file;
        //编译内容
        $head = "<?php if(!defined('TOOK_PATH'))exit;C('SHOW_NOTICE',FALSE);?>";
        if(strpos($content, $head)!==false) {
            $content = $head."\n".$content;
        }
        //创建编译目录与安全文件
        \Tool\Dir::create(dirname($file));
        \Tool\Dir::safeFile(dirname($file));
        //储存编译文件
        file_put_contents($file, $content);
        return $content;
    }

}